<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="laravel-pennant" tabindex="-1"><a class="header-anchor" href="#laravel-pennant"><span>Laravel Pennant</span></a></h2>
<ul>
<li><a href="#introduction">介绍</a></li>
<li><a href="#installation">安装</a></li>
<li><a href="#configuration">配置</a></li>
<li><a href="#defining-features">定义特性</a>
<ul>
<li><a href="#class-based-features">基于类的特性</a></li>
</ul>
</li>
<li><a href="#checking-features">检查特性</a>
<ul>
<li><a href="#conditional-execution">条件执行</a></li>
<li><a href="#the-has-features-trait"><code v-pre>HasFeatures</code> 特性</a></li>
<li><a href="#blade-directive">Blade 指令</a></li>
<li><a href="#middleware">中间件</a></li>
<li><a href="#in-memory-cache">内存缓存</a></li>
</ul>
</li>
<li><a href="#scope">范围</a>
<ul>
<li><a href="#specifying-the-scope">指定范围</a></li>
<li><a href="#default-scope">默认范围</a></li>
<li><a href="#nullable-scope">可空范围</a></li>
<li><a href="#identifying-scope">识别范围</a></li>
<li><a href="#serializing-scope">序列化范围</a></li>
</ul>
</li>
<li><a href="#rich-feature-values">丰富的特性数值</a></li>
<li><a href="#retrieving-multiple-features">检索多个特性</a></li>
<li><a href="#eager-loading">预加载</a></li>
<li><a href="#updating-values">更新数值</a>
<ul>
<li><a href="#bulk-updates">批量更新</a></li>
<li><a href="#purging-features">清除特性</a></li>
</ul>
</li>
<li><a href="#testing">测试</a></li>
<li><a href="#adding-custom-pennant-drivers">添加自定义 Pennant 驱动</a>
<ul>
<li><a href="#implementing-the-driver">实现驱动</a></li>
<li><a href="#registering-the-driver">注册驱动</a></li>
</ul>
</li>
<li><a href="#events">事件</a></li>
</ul>
<h2 id="介绍" tabindex="-1"><a class="header-anchor" href="#介绍"><span>介绍</span></a></h2>
<p><a href="https://github.com/laravel/pennant" target="_blank" rel="noopener noreferrer">Laravel Pennant</a> 是一个简单且轻量级的特性标志包 - 没有多余的东西。特性标志使您能够有信心逐步推出新的应用程序特性、对新界面设计进行 A/B 测试、补充基于主干的开发策略等等。</p>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<p>首先，使用 Composer 包管理器将 Pennant 安装到您的项目中：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require laravel/pennant</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，您应该使用 <code v-pre>vendor:publish</code> Artisan 命令发布 Pennant 的配置和迁移文件：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan vendor:publish <span class="token parameter variable">--provider</span><span class="token operator">=</span><span class="token string">"Laravel\Pennant\PennantServiceProvider"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>最后，您应该运行应用程序的数据库迁移。这将创建一个 <code v-pre>features</code> 表，Pennant 使用它来支持其 <code v-pre>database</code> 驱动：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<p>在发布 Pennant 的资源之后，其配置文件将位于 <code v-pre>config/pennant.php</code>。这个配置文件允许您指定 Pennant 将用于存储已解析的特性标志值的默认存储机制。</p>
<p>Pennant 支持通过 <code v-pre>array</code> 驱动在内存数组中存储已解析的特性标志值。此外，Pennant 还可以通过 <code v-pre>database</code> 驱动将已解析的特性标志值持久存储在关系数据库中，这是 Pennant 默认使用的存储机制。</p>
<h2 id="定义特性" tabindex="-1"><a class="header-anchor" href="#定义特性"><span>定义特性</span></a></h2>
<p>要定义一个特性，你可以使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>define</code> 方法。你需要为特性提供一个名称，以及一个将被调用以解析特性初始值的闭包。</p>
<p>通常，特性在服务提供者中使用 <code v-pre>Feature</code> 门面定义。闭包将接收特性检查的“范围”。最常见的情况是，范围是当前经过身份验证的用户。在这个示例中，我们将为逐步向我们应用程序的用户推出一个新的 API 定义一个特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Bootstrap any application services.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如你所见，我们对特性有以下规则：</p>
<ul>
<li>所有内部团队成员应该使用新的 API。</li>
<li>任何高流量客户不应该使用新的 API。</li>
<li>否则，该特性应随机分配给用户，激活的几率为 1/100。</li>
</ul>
<p>第一次针对给定用户检查 <code v-pre>new-api</code> 特性时，闭包的结果将由存储驱动存储。下次再针对同一用户检查特性时，值将从存储中检索，闭包将不会被调用。</p>
<p>为了方便起见，如果一个特性定义只返回一个抽奖结果，你可以完全省略闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="基于类的特性" tabindex="-1"><a class="header-anchor" href="#基于类的特性"><span>基于类的特性</span></a></h3>
<p>Pennant 还允许你定义基于类的特性。与基于闭包的特性定义不同，无需在服务提供者中注册基于类的特性。要创建一个基于类的特性，你可以调用 <code v-pre>pennant:feature</code> Artisan 命令。默认情况下，特性类将放置在你的应用程序的 <code v-pre>app/Features</code> 目录中：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan pennant:feature NewApi</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>在编写特性类时，你只需要定义一个 <code v-pre>resolve</code> 方法，该方法将被调用以解析给定范围的特性的初始值。同样，范围通常是当前经过身份验证的用户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Features</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">NewApi</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 解析特性的初始值。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">resolve</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>[!NOTE] 特性类通过<a href="https://learnku.com/docs/laravel/11.x/container" target="_blank" rel="noopener noreferrer">容器</a>解析，因此在需要时你可以将依赖项注入到特性类的构造函数中。</p>
</blockquote>
<h4 id="自定义存储的特性名称" tabindex="-1"><a class="header-anchor" href="#自定义存储的特性名称"><span>自定义存储的特性名称</span></a></h4>
<p>默认情况下，Pennant 将存储特性类的完全限定类名。如果你想要将存储的特性名称与应用程序的内部结构解耦，你可以在特性类上指定一个 <code v-pre>$name</code> 属性。该属性的值将代替类名存储：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Features</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">NewApi</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 特性的存储名称。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">string</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$name</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="检查特性" tabindex="-1"><a class="header-anchor" href="#检查特性"><span>检查特性</span></a></h2>
<p>要确定一个特性是否激活，你可以在 <code v-pre>Feature</code> 门面上使用 <code v-pre>active</code> 方法。默认情况下，特性将针对当前经过身份验证的用户进行检查：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 显示资源列表。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>尽管默认情况下特性是针对当前经过身份验证的用户进行检查的，但你可以轻松地针对其他用户或<a href="#scope">范围</a>检查特性。为此，使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>for</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Pennant 还提供了一些额外的便利方法，在确定特性是否激活时可能会很有用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 确定所有给定的特性是否都激活...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">allAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定给定的任何特性是否有激活的...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">someAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定特性是否不激活...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">inactive</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定所有给定的特性是否都不激活...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">allAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定给定的任何特性是否不激活...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">someAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
当在 HTTP 上下文之外使用 Pennant，比如在 Artisan 命令或队列作业中，你通常应该<a href="#specifying-the-scope">明确指定特性的范围</a>。或者，你可以定义一个<a href="#default-scope">默认范围</a>，既考虑到经过身份验证的 HTTP 上下文，也考虑到未经身份验证的上下文。</p>
</blockquote>
<h4 id="检查基于类的特性" tabindex="-1"><a class="header-anchor" href="#检查基于类的特性"><span>检查基于类的特性</span></a></h4>
<p>对于基于类的特性，在检查特性时，你应该提供类名：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Features<span class="token punctuation">\</span>NewApi</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 显示资源列表。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="条件执行" tabindex="-1"><a class="header-anchor" href="#条件执行"><span>条件执行</span></a></h3>
<p><code v-pre>when</code> 方法可用于流畅地执行给定闭包，如果特性是激活的话。此外，可以提供第二个闭包，如果特性不激活，则执行该闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Features<span class="token punctuation">\</span>NewApi</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 显示资源列表。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">when</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>unless</code> 方法作为 <code v-pre>when</code> 方法的反向，如果特性不激活，则执行第一个闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">unless</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="hasfeatures-特性" tabindex="-1"><a class="header-anchor" href="#hasfeatures-特性"><span><code v-pre>HasFeatures</code> 特性</span></a></h3>
<p>Pennant 的 <code v-pre>HasFeatures</code> 特性可以添加到你的应用程序的 <code v-pre>User</code> 模型（或任何其他具有特性的模型）中，以提供一种流畅、方便的方式直接从模型中检查特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>User</span> <span class="token keyword">as</span> Authenticatable<span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Concerns<span class="token punctuation">\</span>HasFeatures</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">HasFeatures</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦将特性添加到你的模型中，你可以通过调用 <code v-pre>features</code> 方法轻松地检查特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，<code v-pre>features</code> 方法还提供了许多其他方便的方法来与特性进行交互：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 值...</span></span>
<span class="line"><span class="token variable">$value</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$values</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 状态...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">someAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">inactive</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">someAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 条件执行...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">when</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">unless</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="blade-指令" tabindex="-1"><a class="header-anchor" href="#blade-指令"><span>Blade 指令</span></a></h3>
<p>为了使在 Blade 中检查特性变得更加无缝，Pennant 提供了一个 <code v-pre>@feature</code> 指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@feature('site-redesign')</span>
<span class="line">    &lt;!-- 'site-redesign' 是激活的 --&gt;</span>
<span class="line">@else</span>
<span class="line">    &lt;!-- 'site-redesign' 是不激活的 --&gt;</span>
<span class="line">@endfeature</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="中间件" tabindex="-1"><a class="header-anchor" href="#中间件"><span>中间件</span></a></h3>
<p>Pennant 还包括一个<a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">中间件</a>，可用于在路由被调用之前验证当前经过身份验证的用户是否有权限访问某个特性。你可以将中间件分配给一个路由，并指定访问该路由所需的特性。如果当前经过身份验证的用户的任何指定特性未激活，则路由将返回一个 <code v-pre>400 Bad Request</code> HTTP 响应。多个特性可以传递给静态的 <code v-pre>using</code> 方法。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Route</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EnsureFeaturesAreActive</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/api/servers'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token class-name static-context">EnsureFeaturesAreActive</span><span class="token operator">::</span><span class="token function">using</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'servers-api'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义响应" tabindex="-1"><a class="header-anchor" href="#自定义响应"><span>自定义响应</span></a></h4>
<p>如果你想要自定义中间件在列出的特性之一未激活时返回的响应，你可以使用 <code v-pre>EnsureFeaturesAreActive</code> 中间件提供的 <code v-pre>whenInactive</code> 方法。通常，此方法应该在你的应用程序的某个服务提供者的 <code v-pre>boot</code> 方法中调用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EnsureFeaturesAreActive</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 引导任何应用服务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">EnsureFeaturesAreActive</span><span class="token operator">::</span><span class="token function">whenInactive</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$features</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token argument-name">status</span><span class="token punctuation">:</span> <span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="内存缓存" tabindex="-1"><a class="header-anchor" href="#内存缓存"><span>内存缓存</span></a></h3>
<p>在检查特性时，Pennant 将创建一个结果的内存缓存。如果你正在使用 <code v-pre>database</code> 驱动程序，这意味着在单个请求中重新检查相同的特性标志将不会触发额外的数据库查询。这也确保了特性在请求的整个持续时间内具有一致的结果。</p>
<p>如果你需要手动刷新内存缓存，可以使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>flushCache</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">flushCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="作用域" tabindex="-1"><a class="header-anchor" href="#作用域"><span>作用域</span></a></h2>
<h3 id="指定作用域" tabindex="-1"><a class="header-anchor" href="#指定作用域"><span>指定作用域</span></a></h3>
<p>正如讨论的那样，通常会针对当前经过身份验证的用户检查特性。然而，这可能并不总是符合你的需求。因此，可以通过 <code v-pre>Feature</code> 门面的 <code v-pre>for</code> 方法指定要针对的作用域以检查给定特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，特性作用域不仅限于“用户”。想象一下，你构建了一个新的计费体验，你要将其推出给整个团队，而不是单个用户。也许你希望最老的团队比较新的团队推出得慢一些。你的特性解析闭包可能如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Team</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Carbon<span class="token punctuation">\</span>Carbon</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Team</span> <span class="token variable">$team</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$team</span><span class="token operator">-></span><span class="token property">created_at</span><span class="token operator">-></span><span class="token function">isAfter</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Carbon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'1st Jan, 2023'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$team</span><span class="token operator">-></span><span class="token property">created_at</span><span class="token operator">-></span><span class="token function">isAfter</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Carbon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'1st Jan, 2019'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你会注意到，我们定义的闭包并不期望一个 <code v-pre>User</code>，而是期望一个 <code v-pre>Team</code> 模型。为了确定这个特性对用户的团队是否激活，你应该将团队传递给 <code v-pre>Feature</code> 门面提供的 <code v-pre>for</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">to</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/billing/v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// ...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="默认作用域" tabindex="-1"><a class="header-anchor" href="#默认作用域"><span>默认作用域</span></a></h3>
<p>你也可以自定义 Pennant 用于检查特性的默认作用域。例如，也许你所有的特性都是针对当前经过身份验证的用户的团队而不是用户进行检查的。你可以将团队指定为默认作用域，而不是每次检查特性时都调用 <code v-pre>Feature::for($user-&gt;team)</code>。通常，这应该在你的应用程序的某个服务提供者中完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 引导任何应用服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">resolveScopeUsing</span><span class="token punctuation">(</span><span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$driver</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果没有通过 <code v-pre>for</code> 方法显式提供作用域，特性检查现在将使用当前经过身份验证的用户的团队作为默认作用域：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 现在等同于...</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="可空作用域" tabindex="-1"><a class="header-anchor" href="#可空作用域"><span>可空作用域</span></a></h3>
<p>如果在检查特性时提供的作用域是 <code v-pre>null</code>，并且特性的定义不支持通过可空类型或在联合类型中包含 <code v-pre>null</code> 来支持 <code v-pre>null</code>，Pennant 将自动将特性的结果值返回为 <code v-pre>false</code>。</p>
<p>如果你将一个可能为 <code v-pre>null</code> 的作用域传递给一个特性，并且希望调用特性的值解析器，你应该在特性的定义中考虑到这一点。如果在 Artisan 命令、队列作业或未经身份验证的路由中检查特性，则可能会出现 <code v-pre>null</code> 作用域。由于在这些情境中通常没有经过身份验证的用户，因此默认作用域将为 <code v-pre>null</code>。</p>
<p>如果你并不总是<a href="#specifying-the-scope">显式指定你的特性作用域</a>，那么你应该确保作用域的类型是“可空的”，并在特性定义逻辑中处理 <code v-pre>null</code> 作用域值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// [tl! remove]</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name">User</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// [tl! add]</span></span>
<span class="line">    <span class="token variable">$user</span> <span class="token operator">===</span> <span class="token constant">null</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span><span class="token comment">// [tl! add]</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="识别作用域" tabindex="-1"><a class="header-anchor" href="#识别作用域"><span>识别作用域</span></a></h3>
<p>Pennant 内置的 <code v-pre>array</code> 和 <code v-pre>database</code> 存储驱动程序知道如何正确存储所有 PHP 数据类型以及 Eloquent 模型的作用域标识符。然而，如果你的应用程序使用第三方 Pennant 驱动程序，该驱动程序可能不知道如何正确存储 Eloquent 模型或应用程序中的其他自定义类型的标识符。</p>
<p>基于此，Pennant 允许你通过在应用程序中用作 Pennant 作用域的对象上实现 <code v-pre>FeatureScopeable</code> 合同来为存储格式化作用域值。</p>
<p>例如，假设你在单个应用程序中使用两种不同的特性驱动程序：内置的 <code v-pre>database</code> 驱动程序和第三方的“Flag Rocket”驱动程序。&quot;Flag Rocket&quot; 驱动程序不知道如何正确存储 Eloquent 模型。相反，它需要一个 <code v-pre>FlagRocketUser</code> 实例。通过实现 <code v-pre>FeatureScopeable</code> 合同中定义的 <code v-pre>toFeatureIdentifier</code> 方法，我们可以自定义提供给应用程序使用的每个驱动程序的可存储作用域值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">FlagRocket<span class="token punctuation">\</span>FlagRocketUser</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>FeatureScopeable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token keyword">implements</span> <span class="token class-name">FeatureScopeable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 将对象转换为给定驱动程序的特性作用域标识符。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">toFeatureIdentifier</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$driver</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">match</span><span class="token punctuation">(</span><span class="token variable">$driver</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token string single-quoted-string">'database'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'flag-rocket'</span> <span class="token operator">=></span> <span class="token class-name static-context">FlagRocketUser</span><span class="token operator">::</span><span class="token function">fromId</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">flag_rocket_id</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="序列化作用域" tabindex="-1"><a class="header-anchor" href="#序列化作用域"><span>序列化作用域</span></a></h3>
<p>默认情况下，Pennant 在存储与 Eloquent 模型关联的特性时将使用完全限定的类名。如果你已经在使用 <a href="https://learnku.com/docs/laravel/11.x/eloquent-relationships#custom-polymorphic-types" target="_blank" rel="noopener noreferrer">Eloquent morph map</a>，你可以选择让 Pennant 也使用 morph map 来将存储的特性与应用程序结构解耦。</p>
<p>为了实现这一点，在服务提供程序中定义了你的 Eloquent morph map 后，你可以调用 <code v-pre>Feature</code> 门面的 <code v-pre>useMorphMap</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Relations<span class="token punctuation">\</span>Relation</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Relation</span><span class="token operator">::</span><span class="token function">enforceMorphMap</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'App\Models\Post'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'video'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'App\Models\Video'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">useMorphMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="丰富的特性值" tabindex="-1"><a class="header-anchor" href="#丰富的特性值"><span>丰富的特性值</span></a></h2>
<p>到目前为止，我们主要展示特性是二进制状态，意味着它们要么是“激活”的，要么是“未激活”的，但 Pennant 也允许你存储丰富的值。</p>
<p>例如，假设你正在测试应用程序“立即购买”按钮的三种新颜色。在特性定义中，你可以返回一个字符串，而不是返回 <code v-pre>true</code> 或 <code v-pre>false</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Arr</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token class-name static-context">Arr</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'blue-sapphire'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'tart-orange'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>value</code> 方法检索 <code v-pre>purchase-button</code> 特性的值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$color</span> <span class="token operator">=</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>Pennant 包含的 Blade 指令还可以根据特性的当前值轻松地有条件地呈现内容：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@feature('purchase-button', 'blue-sapphire')</span>
<span class="line">    &lt;!-- 'blue-sapphire' 激活 --&gt;</span>
<span class="line">@elsefeature('purchase-button', 'seafoam-green')</span>
<span class="line">    &lt;!-- 'seafoam-green' 激活 --&gt;</span>
<span class="line">@elsefeature('purchase-button', 'tart-orange')</span>
<span class="line">    &lt;!-- 'tart-orange' 激活 --&gt;</span>
<span class="line">@endfeature</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
使用丰富的值时，重要的是要知道当特性具有除 <code v-pre>false</code> 之外的任何值时，它被视为「激活」。</p>
</blockquote>
<p>在调用 <a href="#conditional-execution">条件 <code v-pre>when</code></a> 方法时，特性的丰富值将被提供给第一个闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">when</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>同样，在调用条件 <code v-pre>unless</code> 方法时，特性的丰富值将被提供给可选的第二个闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">unless</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="检索多个特性" tabindex="-1"><a class="header-anchor" href="#检索多个特性"><span>检索多个特性</span></a></h2>
<p><code v-pre>values</code> 方法允许检索给定作用域的多个特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// [</span></span>
<span class="line"><span class="token comment">//     'billing-v2' => false,</span></span>
<span class="line"><span class="token comment">//     'purchase-button' => 'blue-sapphire',</span></span>
<span class="line"><span class="token comment">// ]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以使用 <code v-pre>all</code> 方法来检索给定作用域中所有已定义特性的值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// [</span></span>
<span class="line"><span class="token comment">//     'billing-v2' => false,</span></span>
<span class="line"><span class="token comment">//     'purchase-button' => 'blue-sapphire',</span></span>
<span class="line"><span class="token comment">//     'site-redesign' => true,</span></span>
<span class="line"><span class="token comment">// ]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然而，基于类的特性是动态注册的，直到被显式检查之前 Pennant 是不知道它们的。这意味着如果在当前请求期间尚未检查过应用程序的基于类的特性，那么这些特性可能不会出现在 <code v-pre>all</code> 方法返回的结果中。</p>
<p>如果希望确保在使用 <code v-pre>all</code> 方法时始终包含特性类，可以使用 Pennant 的特性发现功能。要开始，请在你的应用程序的一个服务提供程序中调用 <code v-pre>discover</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Bootstrap any application services.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">discover</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>discover</code> 方法将注册应用程序 <code v-pre>app/Features</code> 目录中的所有特性类。<code v-pre>all</code> 方法现在将包含这些类在其结果中，无论它们是否在当前请求期间已被检查：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// [</span></span>
<span class="line"><span class="token comment">//     'App\Features\NewApi' => true,</span></span>
<span class="line"><span class="token comment">//     'billing-v2' => false,</span></span>
<span class="line"><span class="token comment">//     'purchase-button' => 'blue-sapphire',</span></span>
<span class="line"><span class="token comment">//     'site-redesign' => true,</span></span>
<span class="line"><span class="token comment">// ]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="预加载" tabindex="-1"><a class="header-anchor" href="#预加载"><span>预加载</span></a></h2>
<p>尽管 Pennant 为单个请求保留了所有已解析特性的内存缓存，但仍有可能遇到性能问题。为了缓解这一点，Pennant 提供了预加载特性值的能力。</p>
<p>为了说明这一点，假设我们正在循环中检查特性是否处于活动状态：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$users</span> <span class="token keyword">as</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RegistrationSuccess</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>假设我们正在使用数据库驱动程序，这段代码将为循环中的每个用户执行一次数据库查询 - 可能执行数百次查询。然而，使用 Pennant 的 <code v-pre>load</code> 方法，我们可以通过为用户集合或作用域预加载特性值来消除这种潜在的性能瓶颈：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$users</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$users</span> <span class="token keyword">as</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RegistrationSuccess</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要仅在特性值尚未加载时加载特性值，可以使用 <code v-pre>loadMissing</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$users</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">loadMissing</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="更新值" tabindex="-1"><a class="header-anchor" href="#更新值"><span>更新值</span></a></h2>
<p>当特性的值首次解析时，底层驱动程序将结果存储在存储中。这通常是为了确保用户在请求之间获得一致的体验。然而，有时候，您可能希望手动更新特性的存储值。</p>
<p>为此，您可以使用 <code v-pre>activate</code> 和 <code v-pre>deactivate</code> 方法来切换特性的“开”或“关”状态：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 激活默认作用域的特性...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 停用给定作用域的特性...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">deactivate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>也可以通过向 <code v-pre>activate</code> 方法提供第二个参数来手动为特性设置丰富值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要指示 Pennant 忘记特性的存储值，可以使用 <code v-pre>forget</code> 方法。当再次检查特性时，Pennant 将从其特性定义中解析特性的值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">forget</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="批量更新" tabindex="-1"><a class="header-anchor" href="#批量更新"><span>批量更新</span></a></h3>
<p>要批量更新存储的特性值，可以使用 <code v-pre>activateForEveryone</code> 和 <code v-pre>deactivateForEveryone</code> 方法。</p>
<p>例如，假设你现在对 <code v-pre>new-api</code> 特性的稳定性有信心，并已确定了结账流程中最佳的 <code v-pre>'purchase-button'</code> 颜色 - 你可以相应地更新所有用户的存储值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activateForEveryone</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activateForEveryone</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以为所有用户停用特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">deactivateForEveryone</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
这将仅更新已由 Pennant 存储驱动程序存储的已解析特性值。您还需要更新应用程序中的特性定义。</p>
</blockquote>
<h3 id="清除特性" tabindex="-1"><a class="header-anchor" href="#清除特性"><span>清除特性</span></a></h3>
<p>有时，清除存储中的整个特性会很有用。这通常是必要的，如果您已从应用程序中移除了特性，或者您已对特性的定义进行了调整，并希望将其推广给所有用户。</p>
<p>您可以使用 <code v-pre>purge</code> 方法删除特性的所有存储值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 清除单个特性...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">purge</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 清除多个特性...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">purge</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想要从存储中清除 <em>所有</em> 特性，可以调用 <code v-pre>purge</code> 方法而不带任何参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">purge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>作为应用程序部署流水线的一部分清除特性可能很有用，Pennant 包括一个 <code v-pre>pennant:purge</code> Artisan 命令，该命令将清除存储中提供的特性：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan pennant:purge new-api</span>
<span class="line"></span>
<span class="line">php artisan pennant:purge new-api purchase-button</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>还可以清除除了给定特性列表中的特性之外的所有特性。例如，假设您想清除所有特性但保留存储中的「new-api」和「purchase-button」特性的值。为实现此目的，您可以将这些特性名称传递给 <code v-pre>--except</code> 选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan pennant:purge <span class="token parameter variable">--except</span><span class="token operator">=</span>new-api <span class="token parameter variable">--except</span><span class="token operator">=</span>purchase-button</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>为方便起见，<code v-pre>pennant:purge</code> 命令还支持一个 <code v-pre>--except-registered</code> 标志。此标志表示应清除除了在服务提供程序中明确注册的特性之外的所有特性：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan pennant:purge --except-registered</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="测试" tabindex="-1"><a class="header-anchor" href="#测试"><span>测试</span></a></h2>
<p>在测试与特性标志交互的代码时，控制测试中特性标志的返回值最简单的方法是简单地重新定义特性。例如，假设您在应用程序的服务提供程序中定义了以下特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Arr</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token class-name static-context">Arr</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'blue-sapphire'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'tart-orange'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要在测试中修改特性的返回值，可以在测试开始时重新定义特性。以下测试将始终通过，即使 <code v-pre>Arr::random()</code> 的实现仍然存在于服务提供程序中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'it can control feature values'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token function">expect</span><span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_it_can_control_feature_values</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">assertSame</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>对于基于类的特性，可以使用相同的方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'it can control feature values'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token function">expect</span><span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">toBeTrue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Features<span class="token punctuation">\</span>NewApi</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_it_can_control_feature_values</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你的特性返回一个 <code v-pre>Lottery</code> 实例，有一些有用的 <a href="https://learnku.com/docs/laravel/11.x/helpers#testing-lotteries" target="_blank" rel="noopener noreferrer">测试辅助函数可用</a>。</p>
<h4 id="存储配置" tabindex="-1"><a class="header-anchor" href="#存储配置"><span>存储配置</span></a></h4>
<p>你可以通过在应用程序的 <code v-pre>phpunit.xml</code> 文件中定义 <code v-pre>PENNANT_STORE</code> 环境变量来配置 Pennant 在测试期间将使用的存储：</p>
<div class="language-xml line-numbers-mode" data-highlighter="prismjs" data-ext="xml" data-title="xml"><pre v-pre class="language-xml"><code><span class="line"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>phpunit</span> <span class="token attr-name">colors</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    <span class="token comment">&lt;!-- ... --></span></span>
<span class="line">    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>php</span><span class="token punctuation">></span></span></span>
<span class="line">        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>env</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>PENNANT_STORE<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></span>
<span class="line">        <span class="token comment">&lt;!-- ... --></span></span>
<span class="line">    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>php</span><span class="token punctuation">></span></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>phpunit</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="添加自定义-pennant-驱动程序" tabindex="-1"><a class="header-anchor" href="#添加自定义-pennant-驱动程序"><span>添加自定义 Pennant 驱动程序</span></a></h2>
<h4 id="实现驱动程序" tabindex="-1"><a class="header-anchor" href="#实现驱动程序"><span>实现驱动程序</span></a></h4>
<p>如果 Pennant 的现有存储驱动程序都不符合你的应用程序需求，你可以编写自己的存储驱动程序。你的自定义驱动程序应该实现 <code v-pre>Laravel\Pennant\Contracts\Driver</code> 接口：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Extensions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Driver</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">RedisFeatureDriver</span> <span class="token keyword">implements</span> <span class="token class-name">Driver</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">define</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">callable</span> <span class="token variable">$resolver</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">defined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getAll</span><span class="token punctuation">(</span><span class="token keyword type-hint">array</span> <span class="token variable">$features</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">get</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$scope</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">set</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$scope</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">setForAllScopes</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">delete</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$scope</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">purge</span><span class="token punctuation">(</span><span class="token keyword type-declaration">array</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span> <span class="token variable">$features</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在，我们只需要使用 Redis 连接来实现每个方法。要查看如何实现每个方法的示例，请查看 <a href="https://github.com/laravel/pennant/blob/1.x/src/Drivers/DatabaseDriver.php" target="_blank" rel="noopener noreferrer">Pennant 源代码</a> 中的 <code v-pre>Laravel\Pennant\Drivers\DatabaseDriver</code>。</p>
<blockquote>
<p>[!NOTE]<br>
Laravel 不提供一个目录来包含你的扩展。你可以自由地将它们放在任何你喜欢的地方。在这个示例中，我们创建了一个 <code v-pre>Extensions</code> 目录来存放 <code v-pre>RedisFeatureDriver</code>。</p>
</blockquote>
<h4 id="注册驱动程序" tabindex="-1"><a class="header-anchor" href="#注册驱动程序"><span>注册驱动程序</span></a></h4>
<p>一旦你实现了驱动程序，就可以准备将其注册到 Laravel 中。要向 Pennant 添加其他驱动程序，可以使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>extend</code> 方法。应该从应用程序的一个 <a href="https://learnku.com/docs/laravel/11.x/providers" target="_blank" rel="noopener noreferrer">服务提供程序</a> 的 <code v-pre>boot</code> 方法中调用 <code v-pre>extend</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Extensions<span class="token punctuation">\</span>RedisFeatureDriver</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Application</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 注册任何应用程序服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 启动任何应用程序服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Application</span> <span class="token variable">$app</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RedisFeatureDriver</span><span class="token punctuation">(</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token function">make</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token variable">$app</span><span class="token operator">-></span><span class="token function">make</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'events'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦驱动程序已注册，你可以在应用程序的 <code v-pre>config/pennant.php</code> 配置文件中使用 <code v-pre>redis</code> 驱动程序：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'stores'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line"></span>
<span class="line">    <span class="token string single-quoted-string">'redis'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'connection'</span> <span class="token operator">=></span> <span class="token constant">null</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="事件" tabindex="-1"><a class="header-anchor" href="#事件"><span>事件</span></a></h2>
<p>Pennant 分发各种事件，可以在整个应用程序中跟踪特性标志时非常有用。</p>
<h3 id="laravel-pennant-events-featureretrieved" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-featureretrieved"><span><code v-pre>Laravel\Pennant\Events\FeatureRetrieved</code></span></a></h3>
<p>此事件在每次<a href="#checking-features">检查特性</a>时触发。该事件可能对在整个应用程序中创建和跟踪度量标准对特性标志的使用情况很有用。</p>
<h3 id="laravel-pennant-events-featureresolved" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-featureresolved"><span><code v-pre>Laravel\Pennant\Events\FeatureResolved</code></span></a></h3>
<p>第一次为特定范围解析特性值时触发此事件。</p>
<h3 id="laravel-pennant-events-unknownfeatureresolved" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-unknownfeatureresolved"><span><code v-pre>Laravel\Pennant\Events\UnknownFeatureResolved</code></span></a></h3>
<p>第一次为特定范围解析未知特性时触发此事件。监听此事件可能很有用，如果您打算删除一个特性标志，但意外地在整个应用程序中留下了杂乱的引用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Event</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Log</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>UnknownFeatureResolved</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 引导任何应用服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Event</span><span class="token operator">::</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">UnknownFeatureResolved</span> <span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"Resolving unknown feature [<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$event</span><span class="token operator">-></span><span class="token property">feature</span><span class="token punctuation">}</span></span>]."</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="laravel-pennant-events-dynamicallyregisteringfeatureclass" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-dynamicallyregisteringfeatureclass"><span><code v-pre>Laravel\Pennant\Events\DynamicallyRegisteringFeatureClass</code></span></a></h3>
<p>在请求期间首次动态检查<a href="#class-based-features">基于类的特性</a>时触发此事件。</p>
<h3 id="laravel-pennant-events-unexpectednullscopeencountered" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-unexpectednullscopeencountered"><span><code v-pre>Laravel\Pennant\Events\UnexpectedNullScopeEncountered</code></span></a></h3>
<p>当传递给不支持 <code v-pre>null</code> 的特性定义的特性时，将触发此事件。这种情况会被优雅地处理，特性将返回 <code v-pre>false</code>。但是，如果您想要退出此特性的默认优雅行为，可以在应用程序的 <code v-pre>AppServiceProvider</code> 的 <code v-pre>boot</code> 方法中注册此事件的监听器：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Log</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>UnexpectedNullScopeEncountered</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Bootstrap any application services.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Event</span><span class="token operator">::</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token class-name static-context">UnexpectedNullScopeEncountered</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="laravel-pennant-events-featureupdated" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-featureupdated"><span><code v-pre>Laravel\Pennant\Events\FeatureUpdated</code></span></a></h3>
<p>通过调用 <code v-pre>activate</code> 或 <code v-pre>deactivate</code> 更新范围内的特性时触发此事件。</p>
<h3 id="laravel-pennant-events-featureupdatedforallscopes" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-featureupdatedforallscopes"><span><code v-pre>Laravel\Pennant\Events\FeatureUpdatedForAllScopes</code></span></a></h3>
<p>通过调用 <code v-pre>activateForEveryone</code> 或 <code v-pre>deactivateForEveryone</code> 更新所有范围内的特性时触发此事件。</p>
<h3 id="laravel-pennant-events-featuredeleted" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-featuredeleted"><span><code v-pre>Laravel\Pennant\Events\FeatureDeleted</code></span></a></h3>
<p>通过调用 <code v-pre>forget</code> 删除范围内的特性时触发此事件。</p>
<h3 id="laravel-pennant-events-featurespurged" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-featurespurged"><span><code v-pre>Laravel\Pennant\Events\FeaturesPurged</code></span></a></h3>
<p>清除特定特性时触发此事件。</p>
<h3 id="laravel-pennant-events-allfeaturespurged" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-allfeaturespurged"><span><code v-pre>Laravel\Pennant\Events\AllFeaturesPurged</code></span></a></h3>
<p>清除所有特性时触发此事件。</p>
<blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/11.x/pennantmd/16725" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/pe...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/11.x/pennantmd/16725" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/pe...</a></p>
</blockquote>
</div></template>


